<!doctype html>
<html lang="ch">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>在线橡皮擦体验平台</title>
    <!-- 导入bootstrap -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js"></script>
</head>

<body>
    <div class="container">
        <br>
        <!-- 照片上传控件 -->
        <div class="row">
            <div class="offset-md-3 col-md-6 d-flex justify-content-center">
                <input class="form-control" type="file" id="photo_file" accept="image/*">
            </div>
        </div>
        <!-- 画板 -->
        <div class="row">
            <div class="d-flex justify-content-center">
                <!-- 作图画板 -->
                <canvas id="photo_canvas"></canvas> 
                <!-- 掩码图画板（不可见） -->
                <canvas id="mask_canvas" style="display:none"></canvas>
                <!-- 原始图像画板（）不可见 -->
                <canvas id="org_canvas" style="display:none"></canvas>
            </div>
        </div>
        <br>
        <!-- 工具栏控件 -->
        <div class="row">
            <div class="offset-md-3 col-md-4">
                <label class="form-label">画笔粗细</label>
                <input type="range" class="form-range" min="1" max="40" id="paint_range">
            </div>
            <div class="offset-md-1 col-md-4">
                <button type="button" id="btnProcess" class="btn btn-success">修复</button>
            </div>
        </div>
    </div>

    <!-- 全局初始化 -->
    <script>
        image_size = 512; //全局画布大小
        let erasing = false; //是否正在涂抹

        //初始化画图面板
        var photo_ctx = photo_canvas.getContext("2d");
        photo_canvas.width = image_size;
        photo_canvas.height = image_size;
        photo_ctx.fillStyle = "#bbbbbb";
        photo_ctx.fillRect(0, 0, photo_canvas.width, photo_canvas.height);
        let savedImage = null; //用于控制不同的涂抹状态显示效果

        //初始化掩码图面板
        var mask_ctx = mask_canvas.getContext("2d");
        mask_canvas.width = photo_canvas.width;
        mask_canvas.height = photo_canvas.height;
        mask_ctx.fillStyle = "#000000";  //刷新为黑色背景
        mask_ctx.fillRect(0, 0, mask_canvas.width, mask_canvas.height);

        //初始化原图面板
        var org_ctx = org_canvas.getContext("2d");

        //初始化画刷大小
        let radius = 15; 
        document.getElementById("paint_range").value = radius;     
        document.getElementById("paint_range").addEventListener("change", e => {
            radius = parseInt(e.target.value);
        });
    </script>

    <!-- 根据新图像刷新面板状态 -->
    <script>
        function drawFlashImage(image) {
            erasing = false;
            //更新画图面板
            if (image.height > image.width) {
                photo_canvas.height = image_size;
                photo_canvas.width = image_size / (image.height * 1.0 / image.width);
            }
            else {
                photo_canvas.width = image_size;
                photo_canvas.height = image_size / (image.width * 1.0 / image.height);
            }
            photo_ctx.drawImage(image, 0, 0, photo_canvas.width, photo_canvas.height);
            savedImage = photo_ctx.getImageData(0, 0, photo_canvas.width, photo_canvas.height);

            //更新掩码图面板
            mask_canvas.height = photo_canvas.height;
            mask_canvas.width = photo_canvas.width;
            mask_ctx.fillStyle = "#000000";
            mask_ctx.fillRect(0, 0, mask_canvas.width, mask_canvas.height);

            //更新原始图面板
            org_canvas.height = photo_canvas.height;
            org_canvas.width = photo_canvas.width;
            org_ctx.drawImage(image, 0, 0, org_canvas.width, org_canvas.height);
        }
    </script>

    <!-- 照片上传 -->
    <script>
        $(function () {
            $('#photo_file').on('change', function () {
                var r = new FileReader();
                f = document.getElementById('photo_file').files[0];
                r.readAsDataURL(f);
                r.onload = function (e) {
                    var image = new Image();
                    image.src = this.result;
                    image.onload = () => {
                        drawFlashImage(image);         
                    };           
                };
            });
        });
    </script>

    <!-- 画图相关事件 -->
    <script>
        //画板坐标换算
        function windowToCanvas(canvas, x, y) {
            var bbox = canvas.getBoundingClientRect();
            var style = window.getComputedStyle(canvas);
            return {
                x:
                    (x -
                        bbox.left -
                        parseInt(style.paddingLeft) -
                        parseInt(style.borderLeft)) *
                    (canvas.width / parseInt(style.width)),
                y:
                    (y - bbox.top - parseInt(style.paddingTop) - parseInt(style.borderTop)) *
                    (canvas.height / parseInt(style.height))
            };
        }

        //添加橡皮擦相关事件
        photo_canvas.addEventListener("mousedown", e => {
            erasing = true;
        });

        photo_canvas.addEventListener("mousemove", e => {
            const { x, y } = windowToCanvas(photo_canvas, e.clientX, e.clientY);
            if (erasing) {
                erase(x, y);
            }
            else {
                if (savedImage) {
                    photo_ctx.putImageData(savedImage, 0, 0);
                    drawEraser(x, y);
                }
            }
        });

        photo_canvas.addEventListener("mouseup", e => {
            erasing = false;
            savedImage = photo_ctx.getImageData(0, 0, photo_canvas.width, photo_canvas.height);
        });

        photo_canvas.addEventListener("mouseout", e => {
            if (!erasing) {
                if (savedImage) {
                    photo_ctx.putImageData(savedImage, 0, 0);
                }
            }
        });

        //涂抹操作
        function erase(x, y) {
            photo_ctx.save();
            photo_ctx.beginPath();
            photo_ctx.fillStyle = "#ffffff";
            photo_ctx.arc(x, y, radius, 0, Math.PI * 2, true);
            photo_ctx.fill();
            //同时给掩码画板涂抹
            mask_ctx.save();
            mask_ctx.beginPath();
            mask_ctx.fillStyle = "#ffffff";
            mask_ctx.arc(x, y, radius, 0, Math.PI * 2, true);
            mask_ctx.fill();
        }

        function drawEraser(x, y) {
            photo_ctx.beginPath();
            photo_ctx.fillStyle = "#eeeeee";
            photo_ctx.arc(x, y, radius, 0, Math.PI * 2, false);
            photo_ctx.fill();
        }
    </script>

    <!-- 图像修复（发送图像给后端并接收修复结果） -->
    <script>
        //图片转成Buffer
        function dataURItoBlob(dataURI) {
            var byteString = atob(dataURI.split(',')[1]);
            var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
            var ab = new ArrayBuffer(byteString.length);
            var ia = new Uint8Array(ab);
            for (var i = 0; i < byteString.length; i++) {
                ia[i] = byteString.charCodeAt(i);
            }
            return new Blob([ab], { type: mimeString });
        }

        //修复按钮响应事件（使用Ajax发送图像给后端）
        $('#btnProcess').click(function () {
            formdata = new FormData(); //发送数据结构体
            //添加原始图像
            var src = org_canvas.toDataURL("image/png");
            var blob = dataURItoBlob(src);
            formdata.append("image", blob);
            //添加掩码图像
            var mask = mask_canvas.toDataURL("image/png");
            var blob_mask = dataURItoBlob(mask);
            formdata.append("mask", blob_mask);
            //发送数据给后端服务器
            $.ajax({
                url: '/process/',      // 后端API接口
                type: 'POST',          // 请求类型
                data: formdata,
                dataType: 'json',      // 期望获得的响应类型为json
                processData: false,
                contentType: false,
                success: GetResult     // 在请求成功之后调用该回调函数输出结果
            })
        })

        //获取修复后的照片并刷新各面板状态
        function GetResult(data) {
            var v = data['img64'];
            var image = new Image();
            image.src = "data:image/jpeg;base64, " + v;
            image.onload = () => {
                drawFlashImage(image);               
            };
        }
    </script>

</body>
</html>